/**
 * @file ThreadPool.cpp
 * @author zeppyrz (zeppyrz@gmail.com)
 * @brief ThreadPool class implementation
 * @version 0.1
 * @date 2025-11-03
 *
 * @copyright Copyright (c) 2025
 *
 */

#include "ThreadPool.h"

#include <chrono>
#include <deque>
#include <iostream>
#include <thread>

#include "Task.h"
#include "Thread.h"

namespace ZeDisk {

static bool is_exit = false;
static std::deque<Thread *> all_threads_;
static std::mutex all_threads_mutex_;

class ThreadPoolImpl final : public ThreadPool {
 public:
  ThreadPoolImpl();
  explicit ThreadPoolImpl(int thread_count);
  ~ThreadPoolImpl() override = default;

  void Init(int threadCount) override;

  void Dispatch(std::shared_ptr<Task> task) override;

 private:
  std::deque<std::unique_ptr<Thread>> threads_;

  int thread_count_;
  int last_thread_id_;
};

void ThreadPoolImpl::Init(const int threadCount) {
  using namespace std::chrono_literals;
  this->thread_count_ = threadCount;
  for (int i = 0; i < threadCount; i++) {
    auto* t = new Thread(i);
    threads_.emplace_back(t);

    all_threads_mutex_.lock();
    all_threads_.emplace_back(t);
    all_threads_mutex_.unlock();

    if (!t->Start()) {
      std::cout << "[ERROR] ThreadPool::Init() Start Thread Failed"
                << std::endl;
      return;
    }
    std::this_thread::sleep_for(10ms);
  }
  std::cout << "[INFO] ThreadPool::Init() ThreadCount: " << this->thread_count_
            << std::endl;
}

void ThreadPoolImpl::Dispatch(std::shared_ptr<Task> task) {
  if (!task) return;
  // 轮询线程数
  int tid = (last_thread_id_ + 1) % thread_count_;
  last_thread_id_ = tid;
  auto& t = threads_[tid];

  // 添加任务
  task->thread_id() = tid;
  t->AddTask(task);

  // 激活线程
  t->Activate();
}

ThreadPoolImpl::ThreadPoolImpl() : thread_count_(0), last_thread_id_(-1) {}

ThreadPoolImpl::ThreadPoolImpl(int thread_count)
    : thread_count_(thread_count), last_thread_id_(-1) {
  Init(thread_count);
}

void ThreadPool::Exit() {
  is_exit = true;
  std::unique_lock<std::mutex> lck(all_threads_mutex_);
  for (int i = 0; i < all_threads_.size(); i++) {
    all_threads_[i]->Stop();
  }
  all_threads_.clear();
  lck.unlock();
  std::this_thread::sleep_for(std::chrono::milliseconds(200));
}

void ThreadPool::Wait() {
  while (is_exit) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }
}

ThreadPool* ThreadPoolFactory::CreateThreadPool(int threadCount) {
  return new ThreadPoolImpl(threadCount);
}
}  // namespace ZeDisk